/*
 * Copyright (c) 2007, 2008 Johannes Krampf <Johannes.Krampf@htw-dresden.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>

#include "bstring/bstrlib.h"
#include "general.h"
#include "conjugation.h"
#include "language.h"
#include "database.h"
#include "parser.h"

bstring ParseRequest(bstring request) {
	bstring line = NULL;
	struct tagbstring slash = bsStatic("/");
	struct tagbstring underscore = bsStatic("_");
	struct tagbstring get = bsStatic("GET ");
	int pos1, pos2;

	line = bstrcpy(request);
	
	/* Wir brauchen nur die erste Zeile */
	pos1 = bstrchr(line, '\n');
	
	if (BSTR_ERR == pos1) {
		fprintf(stderr, "ParseRequest: Invalide HTTP-Anfrage.\n");
		return NULL;
	}
	
	/* Und unterstützen nur HTTP GET */
	if (0 != bstrncmp(line, &get, 4)) {
		fprintf(stderr, "ParseRequest: Invalide HTTP-Anfrage. Nur GET wird unterstuetzt.\n");
		return NULL;
	}

	/* <GET / HTTP/1.0>
	 * Suche nach dem ersten Leerzeichen von links/rechts. */
	pos1 = bstrchr(line, ' ');
	pos2 = bstrchrp(line, ' ', pos1+1);
	if ((BSTR_ERR == pos1) ||
		(BSTR_ERR == pos1) ||
		(pos1 == pos2) ) {
		fprintf(stderr, "ParseRequest: Invalide GET-Anfrage.\n");
		return NULL;
	}
	
	/* Extrahiere String zwischen den Leerzeichen und entferne alle Leerzeichen */
	bdelete(line, pos2, line->slen-pos2);
	bdelete(line, 0, pos1);
	btrimws(line);

	/* Ersetze / durch den Index */
	if (0 == bstrcmp(&slash, line)) {
		bdestroy(line);
		line = cstr2bstr("index.htm");
	}
	
	
	/* Entferne ein vorgestelltes '/' und ersetze alle '/' durch '_'
	 * Dadurch werden Anfragen auf Dateien außerhalb CWD verhindert */
	if ((0 < line->slen) && ('/' == line->data[0])) {
		bdelete(line, 0, 1);
	}
	bfindreplace (line, &slash, &underscore, 0);

	/* Der Dateityp wird nicht unterstützt, verhindere Zugriff auf die Datenbank */	
	if (0 == (strcmp("text/plain", GetMimeType((char *)line->data)))) {
		fprintf(stderr, "ParseRequest: Unbekannter Dateityp, verweigere Zugriff\n");
		bdestroy(line);
		return NULL;
	}

	return line;
}


char* GetMimeType(char* filename) {
	const char png[4] = "png";
	const char htm[4] = "htm";
	const char css[4] = "css";
	char buffer[128];
	char* pos = NULL;
	
	strncpy(buffer, filename, MinLen(127, strlen(filename)));
	buffer[MinLen(127, strlen(filename))] = '\0';
	
	/* Entferne eventuelle GET-Anfragen */
	pos = strchr(buffer, '?');
	if (NULL != pos) {
		buffer[pos-buffer] = '\0';
	}

	if (0 == (strncmp(png, buffer+(strlen(buffer)-3), 3))) {
		return "image/png";
	}

	if (0 == (strncmp(htm, buffer+(strlen(buffer)-3), 3))) {
		return "text/html";
	}

	if (0 == (strncmp(css, buffer+(strlen(buffer)-3), 3))) {
		return "text/css";
	}
	
	return "text/plain";
}

bstring DynamicRequest(char* request) {
	char buffer[128];
	char* pos = NULL;
		
	pos = strchr(request, '?');
	
	if (NULL == pos) {
		return NULL;
	}

	if ((strlen(request)>request-pos+5) && (0 != strncmp("verb=", pos, 5))) {
		return NULL;
	}
	
	strncpy(buffer, request, MinLen(127, strlen(request)));
	buffer[MinLen(127, MinLen(strlen(request),pos-request))] = '\0';

	return ParseTemplate(buffer, pos+6);
}

bstring ParseTemplate(char* template, char* verb) {
	bstring btemplate = cstr2bstr("");
	bstring verbliststr = NULL;
	bstring verblist = cstr2bstr("");
	char buffer[128];
	char* tempchar = NULL;
	struct language* lang;
	bstring temp = NULL, temp2 = NULL;
	int pos1, pos2, i;
	struct tagbstring TITLE = bsStatic("$TITLE$");
	struct tagbstring VERB = bsStatic("$VERB$");
	struct tagbstring VSTART = bsStatic("$!");
	struct tagbstring VEND = bsStatic("!$");
	struct tagbstring CSTART = bsStatic("$(");
	int count = 0, failed = 0;

	temp = GetFileContent(template);
	if (NULL == temp) {
		return NULL;
	}
	bconcat(btemplate, temp);
	temp = NULL;

	strncpy(buffer, template, MinLen(127, strlen(template)));
	buffer[MinLen(127, strlen(template))] = '\0';

	/* Entferne Dateiendung */
	buffer[strlen(buffer)-4] = '\0';

	lang = GetLanguage(buffer);
	if (NULL == lang) {
		bdestroy(btemplate);
		return NULL;
	}

	pos1 = binstr(btemplate, 0, &VSTART);
	pos2 = binstr(btemplate, pos1+2, &VEND);

	verbliststr = bmidstr(btemplate, pos1+2, pos2-pos1-2);
	if (NULL != verbliststr) {
		bdelete(btemplate, pos2, 2);
		bdelete(btemplate, pos1, 2);
		for (i=0;i<lang->numverbs;i++) {
			temp2 = bstrcpy(verbliststr);
			temp = cstr2bstr(lang->verbs[i]);
			bfindreplace(temp2, &VERB , temp, 0);
			bdestroy(temp);
			bconcat(verblist, temp2);
			bdestroy(temp2);
		}
		bfindreplace(btemplate, verbliststr , verblist, 0);
		bdestroy(verbliststr);
		bdestroy(verblist);
	}

	strcpy(buffer, lang->name);
	strcat(buffer, " - ");
	strcat(buffer, verb);
	temp = cstr2bstr(buffer);

	bfindreplace(btemplate, &TITLE , temp, 0);
	bdestroy(temp);
	temp = NULL;

	strcpy(buffer, verb);
	temp = cstr2bstr(buffer);
	bfindreplace(btemplate, &VERB , temp, 0);
	bdestroy(temp);

	pos1 = binstr(btemplate, 0, &CSTART);
	while (BSTR_ERR != pos1) {
		pos2 = bstrchrp(btemplate, ')', pos1+1);
		if (BSTR_ERR == pos2) {
			break;
		}
		
		if ((6 == pos2-pos1) || (8 == pos2-pos1)) {
			strncpy(buffer,(char *)btemplate->data+pos1+2, 6);
			buffer[6] = '\0';
			buffer[4] = '\0';

			if (6 == pos2-pos1) {
				buffer[5] = 0;
			}
			count++;
			tempchar = ConjugateVerb(verb, buffer, atoi(buffer+5), lang);
			if (0 != strcmp("", tempchar)) {
				temp = cstr2bstr(tempchar);
				free(tempchar);
				bdelete(btemplate, pos1, pos2-pos1+1);
				binsert(btemplate, pos1, temp, ' ');
				bdestroy(temp);
			}else {
				failed++;
			}
		}
		pos1 = binstr(btemplate, pos1+1, &CSTART);	
	}

	if (0 < failed) {
		fprintf(stderr, "ParseTemplate: %d/%d Formen fuer %s nicht gefunden.\n", failed, count, verb);
		if(count == failed) {
			bdestroy(btemplate);
			btemplate = GetFileContent("index.htm");
			fprintf(stderr, "ParseTemplate: Ausgabe von index.htm\n");
		}
	}

	return btemplate;
}
